import org.w3c.dom.ls.LSOutput;

import java.util.Arrays;
import java.util.MissingFormatArgumentException;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 何华树
 * Date: 2024-05-14
 * Time: 15:52
 */
public class 数组 {
    public static void main1(String[] args) {

        //一维数组的几种定义方式
        // c语言的定义数组的方式：int arr[]
        // java 当中
        int[] arr = {1, 2, 3, 4, 5}; // java当中独有的，int[] 是数组的类型
        int[] array = new int[3]; // 运用了关键字 new ，创建了新的数组对象，没有初始化，默认里面都是0；
        int[] array1 = new int[]{1, 2, 3, 4, 5}; // 创建了新的数组对象，但注意，[]里面不能写数字
        int arr1[] = {1, 2, 3, 4, 5};// java支持 c语言的数组定义方式，但是在java当中，不推荐

        //初始化整个数组的操作，只有在数组 定义 的时候，才可以进行初始化，不能分开
        //如：int [] arr = new int [];
        //  arr = ｛1,2，3｝；（错误）

        //数组没有初始化，有默认值，大部分为 0
        //但是 boolean（布尔）类型的默认值为 false
    }

    public static void main2(String[] args) {
        //数组元素的访问：与 C语言的完全相同，默认下标 从0开始
        int[] arr = {1,2,3,4,5};
        System.out.println(arr[1]);//2
    }

    public static void main3(String[] args) {
        //java 里面 没有 sizeof关键字，使用 数组名.length 来求取整个数组的长度
        int[] arr1 = new int[]{1,2,3};
        System.out.println(arr1.length); // 3
    }

    public static void main4(String[] args) {
        //java 当中 遍历数组的方法

        //第一种 : 使用循环遍历
        int[] arr = {1,2,3,4,5};
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
        System.out.println("=====");

        //第二种： for each 循环
        int[] array = new int[]{1,2,3,4,5};
        for (int x:array) {    //遍历数组的每个元素，把每个元素放在变量 x 当中，x会被数组元素依次覆盖
            System.out.print(x+" "); //打印 x 里面放的元素
        }
        System.out.println();
        System.out.println("=====");

        //第三种：操作数组的工具类：Arrays.toString(数组名)
        //    使用 Arrays.toString(array1) 把传入的参数 array1 表示的数组，以字符串的形式输出
        int[] array1 = new int[]{1,2,3,4,5};
        System.out.println(Arrays.toString(array1));
    }

    public static void main5(String[] args) {
        //理解数组是引用变量
        int[] arr = {1,2,3};
        //int[] 叫做引用类型，而 arr 叫做 引用变量 或者 引用，而后面的 {1,2,3} 叫做对象

        String str = "abc";
        // String 叫做引用类型，而 str 叫做 引用变量 或者 引用，而后面的 ”abc“，叫做对象

        //如何理解 引用和对象 呢？
        //比如C语言中的指针，int* p = &a;
        // int* 是指针类型，p叫做指针变量（指针），存放的是 变量a 的地址，所以 p 可以 指向 a。
        // 引用和对象，也可以这么理解
        // int[] 是引用类型，arr叫做引用变量（引用），存放的是 数组首元素 的地址，所以，arr可以指向数组对象 {1,2,3}
        System.out.println(arr[0]);// 通过 arr 这个引用，访问当前这个对象的 0下标
        System.out.println(arr.length);// 通过 arr 这个引用，访问当前这个对象的长度

        //引用在存储中，在 栈 上创建，对象 在堆上创建
        //引用变量，并不是直接存储对象本身，而是存储 对象在堆中创建后的 起始地址 ，通过该地址，引用变量 便可以 操作对象
    }

    public static void main6(String[] args) {
        //代码练习： 定义两个数组，然后 数组1==数组2 ，接着运用数组1，去修改 数组2 的对象
        int[] arr1 = {1,2,3,4,5};
        int[] arr2 = {0,0,0,0,0};
        arr2[0] = 90;
        arr2[1] = 80;
        arr1 = arr2;//此时，arr1 和 arr2 均指向 arr2 的对象。
        // 此时，任何一个引用，都能去改变 对象 的值。
        //如果 {1,2,3,4,5} 这个对象，一直没有使用的话，会被操作系统自动回收
        arr1[2] = 70;
        arr1[3] = 60;
        arr1[4] = 50;
        System.out.println(Arrays.toString(arr2));
        System.out.println(Arrays.toString(arr1));
        //此时，这两个打印的结果是一样的，因为 arr1 和 arr2 指向同一个对象
    }

    public static void main7(String[] args) {
        //
        int[] arr = null;//这个代码的意思是：arr 这个引用，不指向任何对象，和 C语言 的空指针（NULL）一样
//        System.out.println(arr[0]);
//        java.lang.NullPointerException     空指针异常，
        //如果将来，遇到了空指针异常，我们要做的是找到这行代码的 引用， 判断为什么这个引用是空的
    }

    public static int[] func1(int[] arr1) {
        for (int i = 0; i < arr1.length; i++) {
            arr1[i] *= 2;
        }
        return arr1;
    }
    public static int[] func2(int[] arr2) {
        int[] arr3 =new int[arr2.length];//这个数组没有初始化，里面默认都是 0；
        for (int i = 0; i < arr2.length; i++) {
            arr3[i] = arr2[i]*2;
        }
        return arr3;
    }
    public static void main8(String[] args) {
        //代码练习：把一个数组当中的每个元素都扩大 2倍
        //  java当中，1.数组可以做形参 2。方法可以返回整个数组
        //两种方法：1.改变数组本身 2.新建立一个数组，把数组的每个元素扩大2倍的值放在里面

        //方法1：改变数组本身
        int[] arr1 = {1,2,3,4,5};
        System.out.println(Arrays.toString(func1(arr1)));
        System.out.println();
        System.out.println("========");

        //方法2：不改变数组本身，新建立一个数组，把数组的每个元素扩大2倍的值放在里面
        int[] arr2 = {1,2,3,4,5};
        System.out.println(Arrays.toString(arr2));

        System.out.println(Arrays.toString(func2(arr2)));
    }

    public static void func3(int[] arr) {//在函数里，通过引用，访问数组对象的第一个元素，并修改它的值
             arr[0] = 99;
    }
    public static void func4(int[] arr1) { //在函数里，创建新的数组对象，当函数结束后，该数组对象就被系统自动回收了
        arr1 = new int[]{9,8,7,6,5};
    }

    public static void main9(String[] args) {
        //代码验证：是不是传引用就能改变实参的值 (结论：一个引用不可能指向多个对象)
        int []arr = new int[]{1,2,3,4,5};
        func3(arr); //通过传引用，成功修改数组第一个元素的值，为 99
        func4(arr); //通过传引用，在函数里创建新的数组对象，但函数接受后就被销毁（回收）了，对原来的数组对象没有任何影响
        System.out.println(Arrays.toString(arr));
    }

    public static void main10(String[] args) {
        //  结论：
        // 1.int[] arr = null;这个引用不指向任何对象   在 main7 验证
        // 2.arr1 = arr2; 这两个引用，指向同一个对象。  在 main6 验证
        // 3.一个引用不可能指向多个对象。               在 main9 验证
    }

    public static void main11(String[] args) {
        //把数组以字符串的形式输出
        int[] arr = new int[]{1,2,3,4,5};
        System.out.println(Arrays.toString(arr));
    }

    public static void myTostring(int[] arr) {
        String ret = "[";
        for (int i = 0; i < arr.length; i++) {
            ret += arr[i]; //注意：这里的 “ + ”，表示拼接的功能
            if(i != arr.length-1) {
                ret +=",";
            }
        }
        ret += "]";
        System.out.println(ret);
    }
    public static void main12(String[] args) {
        //模拟实现 Arrays.toString(arr) （现实中，直接用就好了，完全没必要模拟实现，这个只是锻炼一下思维）
        int[] arr = new int[]{9,8,7,6,5};
        myTostring(arr);
    }

    public static int func(int[] arr,int input) { //逐个查找
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] == input) {
                return i;
            }
        }
        return -1;
    }
    public static int binarySearch(int[] array,int input) { //使用二分查找
        int left = 0;
        int right = array.length-1;
        int mid = 0;
        Arrays.sort(array);//对数组进行排序，默认从下到大
        while (left <= right) {
            mid = (left+right)/2;
            if(array[mid]>input) {
                right = mid-1;
            }else if(array[mid]<input) {
                left = mid+1;
            }else{
                return mid;
            }
        }
        return -1;
    }
    public static void main13(String[] args) {
        //   查找数组元素
        // 1.逐个查找，循环遍历对比（效率低下）
        // 2.二分查找

        //第一种：逐个查找
        int[] arr = new int[]{1,2,3,4,5,6,7,8,9,10};
        Scanner s = new Scanner(System.in);
        int input = s.nextInt();
        int ret = func(arr,input);
        System.out.println("查找的数字的下标是："+ret);

        System.out.println("=================");
        //第二种：二分查找(只适用于 有序数组，如果开始就是乱序的，需要先进行排序，可以用数组工具方法：Arrays.sort())
        int input1 = s.nextInt();
        int[] array = new int[]{2,3,5,7,1,4,8,6,9,0};
        int ret1 = binarySearch(array,input1);
        System.out.println("查找的数字的下标是："+ret);
    }

    public static void bublle_sort(int[] arr) {
        int flag = 0;
        for (int i = 0; i < arr.length-1; i++) {
            int j = 0;
            flag = 1;//假设开始就是有序的数组
            for(j=0;j < arr.length-1-i;j++) {
                if(arr[j]>arr[j+1]) {
                    flag = 0;
                    int tem = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tem;
                }
            }
            if(flag == 1){ //如果一趟完整的冒泡排序，flag都没有改变成 0，说明这个数组本身就已经有序了；
                return;
            }
        }
    }
    public static void main14(String[] args) {
        //数组排序
        // 1.冒泡排序
        // 2.数组工具的方法：Arrays.sort()

        //第一种：冒泡排序
        int[] arr = new int[]{3,8,6,9,10,7,4,5,2,1};
        bublle_sort(arr);
        System.out.println(Arrays.toString(arr));

        System.out.println("================");

        //第二种：数组排序工具的方法：Arrays.sort()
        int[] arr1 = new int[]{1,2,5,7,9,3,8,5,6,10,90,78,56,84,38};
        Arrays.sort(arr1);
        System.out.println(Arrays.toString(arr1));
    }

    public static void main15(String[] args) {
        //JAVA 提供了一个二分查找的工具：
        int[] array = new int[]{1,2,3,4,5,6,7,8,9,10};
        System.out.println("你要查找的数字的下标是："+Arrays.binarySearch(array,4));
        //这种是在整个数组范围里面找
        System.out.println("在范围寻找的数字的下标是："+Arrays.binarySearch(array,0,4,3));
        //这种是在 下标[0,4)，范围里面去找，这个范围是包括 0~3的，不包括4
        // 而 5 的 下标是4，所以，返回的是个 随机负数
    }
    public static int[] arraycopy(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i+1;
        }
        return arr;
    }
    public static void main16(String[] args) {
        //数组拷贝（定义方法，定义新数组，循环赋值）
        int[] array = new int[10];
        array = arraycopy(array);
        int[] array1 = array;//此时，两个引用指向同一个变量
        System.out.println(Arrays.toString(array1));
        System.out.println(Arrays.toString(array));
        //这两个打印的结果是 一样的。
    }

    public static void main17(String[] args) {
        //数组拷贝：java里面，提供了数组拷贝的很多工具
        int[] arr = new int[]{1,2,3,4,5};
        int[] arr1 =new int[5];
        int[] arr2 =new int[5];
        int[] arr3 =new int[5];

        //接受拷贝完成的数组（copy） = Arrays.copyOf(（扩容）拷贝的数组,接受拷贝完成的数组（copy）的长度)
        arr1 = Arrays.copyOf(arr,10);
        System.out.println(Arrays.toString(arr1));
        System.out.println("=====================");

        //范围拷贝：Arrays.copyOfRange(arr,(拷贝的数组),拷贝的数组的起始下标，拷贝的数组的末下标(决定数组的长度))；
        arr2 = Arrays.copyOfRange(arr,0,3);
        //arr拷贝过去的是：[0,3)的范围的元素，包括 0~2，不包括 3 下标的元素
        System.out.println(Arrays.toString(arr2));

        System.out.println("=====================");
    }

    public static void main18(String[] args) {
        //简单使用Arrays.equals(数组1，数组2)   比较数组内容是否完全一样   返回类型是布尔类型   两个数组的类型必须相同
        int[] arr = new int[]{1,2,3};
        int[] arr1 = new int[]{1,2,3};
        boolean ret = Arrays.equals(arr,arr1);
        System.out.println(ret);
    }

    public static void main19(String[] args) {
        //简单使用 Arrays.fill(数组名，（n）替换的元素)；  将数组元素全部替换成 n
        int[] arr = new int[]{1,2,3};
        Arrays.fill(arr,-1);   //将数组里面的全部元素替换成 -1
        System.out.println(Arrays.toString(arr));
    }

    public static void main20(String[] args) {
        // 二维数组 的定义，和输出
        //定义：
//        int[][] arr = {1,2,3,4,5,6,7,8,9};//错误的定义方式，在 C语言 中，这种方式，编译器会自动区分，但是在 java 里面不可以
        int[][] arr1 = {{1,2,3},{4,5,6},{7,8,9}};  //正确的定义方式，这样表示的是：3行3列的二维数组。
        int[][] arr2 = new int[][]{{1,2,3},{4,5,6},{7,8,9}};//正确的定义方式，这样表示的是：3行3列的二维数组。
        int[][] arr3 = new int[3][3];//正确的定义方式，这样表示的是：3行3列的二维数组。里面的元素默认都是 0
        int[][] arr4 = new int[3][];//不规则二维数组，java里面，二维数组可以不写列，但是必须写列。

        //输出
        System.out.println(Arrays.toString(arr1[0]));// [1,2,3]
        // 现在打印的是二维数组的第一个元素，
        // 证明，二维数组本身是一个特殊的一维数组，存放的是 一维数组。
        System.out.println(arr1.length);//  3
        // 二维数组 行 的个数 --->  等价 于 存放的一维数组的个数
        System.out.println(arr1[0].length);//  3
        // 二维数组 列 的个数 --->  等价 于 这一行（第 0 行）存放的这一个 一维数组 里面的 元素个数

        //深度打印
        System.out.println(Arrays.deepToString(arr1));//直接打印二维数组 的全部元素。

        //循环输出
        for (int i = 0; i < arr1.length; i++) { //限制二维数组的 行
            for (int j = 0;j < arr1[0].length;j++) {  //限制二维数组的 列
                System.out.print(arr1[i][j]+" ");
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        //此时不能确定二维数组的列，当你循环访问数组的时候，会产生空指针异常
        int[][] arr = new int[2][];
        for (int j = 0;j<arr.length;j++) {
            for (int i = 0; i < arr[0].length; i++) {
                System.out.print(arr[j][i]);
            }
            //解决方法：1.可以在[2][],在第二个空格那里确定一个数字，确定列
            //        2.定义一个不规则的二维数组

            //定义一个不规则的二维数组
            int[][] arr1 = new int[2][];
            arr1[0] = new int[3]; //对二维数组存放的第一个一维数组，确定长度为 3，同时也确定，第一行的列数为 3。
            arr1[1] = new int[5]; //对二维数组存放的第二个一维数组，确定长度为 5，同时也确定，第一行的列数为 5。
        }
    }
}
